/**
 * Contains all Objects and layers
 * objects[0]: {
 		dom:			DOM-Object
		ctx:			Canvas-Context
		properties:		{}
		elements:
			[0]: {
					type:		'string',
					value:		'Hello world',
					x:			10,
					y:			10,
					z-index:	0
				 }
		lastElement: 0
 	}
 * lastIndex: 0
 */
var jQuanvasObjects = {
	objects:	[],
	lastIndex:	-1
}

/**
 * Initialication-Function
 * @param object properties	contains properties
 							width, height
 */
jQuery.fn.canvas = function(properties){
	this.each(function() {

		// Check if given object is canvas-object
		if (this.tagName != "CANVAS")
			return false;

		// Get canvas-context
		var ctx = this.getContext('2d');

		// Set properties
		if (properties.width)
			jQuery(this).attr('width', properties.width);
		else
			properties.width	= jQuery(this).width();

		if (properties.height)
			jQuery(this).attr('height', properties.height);
		else
			properties.height	= jQuery(this).height();

		var index = jQuery.canvasAddDom(this, ctx, properties)

		jQuery(this).data('canvasIndex', index);
	});
}

jQuery.canvasLayer = function(layer, properties) {
	if (!layer)
		return false;

	if (!properties)
		properties = {};

	if (layer.obj)
		var dom = layer.obj.dom;
	else
		var dom = layer;

	// Check properties
	if (!properties.width)
		properties.width	= jQuery(dom).width();
	if (!properties.height)
		properties.height	= jQuery(dom).height();
	if (!properties.clip)
		properties.clip = false;

	return jQuery.canvasAddObject(layer, 'layer', properties);
}

jQuery.canvasRect = function(layer, properties) {
	if (!layer)
		return false;
	
	if (!properties)
		properties = {};
	
	if (layer.obj)
		var dom = layer.obj.dom;
	else
		var dom = layer;

	// Check properties
	if (!properties.width)
		properties.width	= jQuery(dom).width();
	if (!properties.height)
		properties.height	= jQuery(dom).height();

	return jQuery.canvasAddObject(layer, 'rect', properties);
}

/**
 * Adds text to an canvas-object
 */
jQuery.canvasText = function(layer, str, properties) {
	_layer	= layer;
	_str	= str;

	if (typeof layer == 'string')
		_str	= layer;
	if (typeof str == 'object' && typeof layer == 'string')
		_layer	= str;
	if (typeof str == 'object' && typeof layer == 'object' && typeof properties == 'undefined')
		properties	= str;
	
	layer	= _layer;
	str		= _str;

	if (!properties)
		properties = {};
	
	// Check properties
	if (!properties.value)
		properties.value	= str;
	if (!properties.fill)
		properties.fill		= "#000";

	return jQuery.canvasAddObject(layer, 'string', properties);
}

/**
 * Adds DOM-Element to list
 */
jQuery.canvasAddDom = function(dom, ctx, properties) {
	// Get new index
	var index = ++jQuanvasObjects.lastIndex;

	jQuanvasObjects.objects[index] = {
		'dom':			dom,
		'ctx':			ctx,
		'properties':	properties,
		'elements':		[],
		'lastElement':	-1
	}

	return index;
}

/**
 * Adds object to object-list
 * @param object layer		contains layer-object
 * @param string type		type of object
 * @param object properties
 */
jQuery.canvasAddObject = function(layer, type, properties)
{
	if (!layer || !properties)
		return false;

	// Check given layer
	if (layer.data)
	{
		var index	= layer.data('canvasIndex');
		layer		= jQuanvasObjects.objects[index];
	}
	else if (layer.index != undefined && layer.obj != undefined)
		layer		= layer.obj;
	else
		return false;

	// object what gets added to list
	var obj			= {};

	switch(type) {
		case 'layer':
			obj.elements	= [];
			obj.lastElement	= -1;
			break;
	}

	// check default-properties
	if (!properties.x)
		properties.x		= 0;
	if (!properties.y)
		properties.y		= 0;

	// set object
	obj.type				= type;
	obj.dom					= layer.dom;
	obj.ctx					= layer.ctx;
	obj.parent				= layer;
	obj.properties			= properties
	obj.zIndex				= 0;

	var index	= ++layer.lastElement;
	//alert(layer.elements);
	layer.elements[index]	= obj;

	// redraw scene
	jQuery.canvasDraw();

	return {
		'obj':		layer.elements[index],
		'index':	index,
		'set':		function(a, b) {
			this.obj.properties[a] = b;
		},
		'get':		function(a) {
			return this.obj.properties[a];
		}
	};
}

/**
 * Draws all elements
 * @param object obj Start-object - leave empty to draw everything
 */
jQuery.canvasDraw = function(obj, cLeft, cTop) {
	// Current draw-position
	if (!cLeft)
		cLeft	= 0;
	if (!cTop)
		cTop	= 0;

	// Check obj
	if (!obj)
		return jQuery.canvasInitDraw();
	if (obj.elements == undefined && obj.tagName == 'CANVAS')
	{
		var index	= jQuery(obj).data('canvasIndex');

		// Reset canvas-object
		jQuery.canvasReset(index);

		var startX	= 0;
		var startY	= 0;
		if (jQuanvasObjects.objects[index].properties.pixel)
		{
			startX	= 0.5;
			startY	= 0.5;
		}

		// Draw elements
		var result	= jQuery.canvasDraw(jQuanvasObjects.objects[index], startX, startY);

		// Restore canvas-object
		jQuery.canvasRestore(index);
	}

	var elm = 0;
	for (elm in obj.elements) {
		var current	= obj.elements[elm];

		// Save state
		current.ctx.save();

		var tmpLeft	= cLeft + current.properties.x;
		var tmpTop	= cTop + current.properties.y;

		switch (current.type) {
			case 'layer':
				if (current.properties.clip == true)
				{
					current.ctx.rect(tmpLeft, tmpTop, current.properties.width, current.properties.height);
					current.ctx.clip();
				}

				jQuery.canvasDraw(current, tmpLeft, tmpTop);

				break;

			case 'rect':
				if (current.properties.fill) {
					current.ctx.fillStyle	= current.properties.fill;
					current.ctx.fillRect(tmpLeft, tmpTop, current.properties.width, current.properties.height);
				}
				if (current.properties.stroke) {
					current.ctx.strokeStyle	= current.properties.stroke;
					current.ctx.strokeRect(tmpLeft, tmpTop, current.properties.width, current.properties.height);
				}
				break;

			case 'string':
				var value	= current.properties.value;
				
				// Set font
				if (current.properties.font)
					current.ctx.font			= current.properties.font;
				if (current.properties.baseline)
					current.ctx.textBaseline	= current.properties.baseline;

				if (current.properties.fill) {
					current.ctx.fillStyle	= current.properties.fill;
					current.ctx.fillText(value, tmpLeft, tmpTop);
				}
				if (current.properties.stroke) {
					current.ctx.strokeStyle	= current.properties.stroke;
					current.ctx.strokeText(value, tmpLeft, tmpTop);
				}

				break;
		}

		// Restore state
		current.ctx.restore();
	}
}

/**
 * Reads all dom-objects and starts drawing
 */
jQuery.canvasInitDraw = function() {
	for (o in jQuanvasObjects.objects) {
		var current	= jQuanvasObjects.objects[o];

		// Reset canvas-object
		jQuery.canvasReset(o);

		var startX	= 0;
		var startY	= 0;
		if (jQuanvasObjects.objects[o].properties.pixel)
		{
			startX	= 0.5;
			startY	= 0.5;
		}

		// Draw elements
		jQuery.canvasDraw(current, startX, startY);

		// Restore canvas-object
		jQuery.canvasRestore(o);
	}
}

/**
 * Resets scene of given object
 * @param int index contains index of canvas-dom-object
 */
jQuery.canvasReset = function(index) {
	if (!index)
		return false;

	var cObject	= jQuanvasObjects.objects[index];
	var ctx		= cObject.ctx;

	var width	= cObject.properties.width;
	var height	= cObject.properties.height;

	ctx.globalCompositeOperation = 'source-over';
	ctx.clearRect(0, 0, width, height);

	ctx.fillStyle		= '#ffffff';
	ctx.strokeStyle		= '#000000';
	ctx.font			= "normal 12px monospace";
	ctx.textBaseline	= "top";

	ctx.save();
}

/**
 * Restores status of given object
 * @param int index contains index of canvas-dom-object
 */
jQuery.canvasRestore = function(index) {
	if (!index)
		return false;

	var cObject	= jQuanvasObjects.objects[index];
	var ctx		= cObject.ctx;

	ctx.restore();
}

__debug = function(str) {
	jQuery("#debug").append(str+"\n");
}
